﻿using NPinyin;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

public class VoiceRecognitionInterface : MonoBehaviour
{
    string[] keywords;
    List<Seg> segs = new List<Seg>();
    List<GameObject> resultGos = new List<GameObject>();
    int segOffset = 0;
    bool matchPinyin = false;
    public float silentTime = 0;
    float recogStartTime = 0;
    bool silentFromStart = false;

    class Seg
    {
        public int id;
        public string str;

        public Seg()
        {
            id = -1;
            str = "";
        }
    }

    public class Output
    {
        public bool[] hasKeys;
        public string words;
        public string pinyins;
        public Output() { }
    }

    // Start is called before the first frame update
    void Start()
    {
        keywords = new string[0];
        segOffset = 0;
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void VoiceRecognitionInterface_StartRecognition(string[] _keywords)
    {
        keywords = new string[_keywords.Length];
        for (int i = 0; i < _keywords.Length; i++)
            keywords[i] = _keywords[i];
        SendMessage("VoiceRecognitionStart");
        segs.Clear();
        segs.Add(new Seg());
        segOffset = 0;
        silentFromStart = true;
        recogStartTime = Time.time;
        silentTime = 0;
//        print(string.Format("txtSegs Num:{0}", segs.Count));
    }

    public void VoiceRecognitionInterface_StopRecognition()
    {
        silentFromStart = false;
        silentTime = 0;
        SendMessage("VoiceRecognitionStop");
    }

    void OnVoiceRecognitionIndexed_NoResponse()
    {
        foreach (GameObject go in resultGos)
            go.SendMessage("OnVoiceRecognitionInterface_NoResponse", SendMessageOptions.DontRequireReceiver);
    }

    void OnSilence()
    {
        if (segs[segs.Count - 1].id >= 0)
            segs.Add(new Seg());
        else
            segOffset++;

        if (silentFromStart)
            silentTime = Time.time - recogStartTime;
//        print(string.Format("txtSegs Num:{0}", segs.Count));
    }

    public void Register(GameObject go)
    {
        bool got = false;
        for (int i = 0; i < resultGos.Count; i++)
            if (resultGos[i] == go)
                got = true;
        if (!got)
            resultGos.Add(go);
    }

    public void Unregister(GameObject go)
    {
        for (int i = 0; i < resultGos.Count; i++)
            if (resultGos[i] == go)
            {
                resultGos.RemoveAt(i);
                break;
            }
    }

    public void SetMatchPinyin(bool en)
    {
        matchPinyin = en;
    }

    void OnVoiceRecognitionIndexed_Result(Dictionary<string, string> results)
    {
        string prt = "";
        prt += string.Format("index:" + results["index"]);
        prt += string.Format(",seg:" + results["seg"]);
        prt += string.Format(",result:" + results["result"]);
        print(prt);

        int index = int.Parse(results["index"]);
        int seg = int.Parse(results["seg"]);
        int segActual = seg - segOffset;
        if (results["result"].Length>0)
        {
            if(segs[segActual].id<index)
            {
                segs[segActual].id = index;
                segs[segActual].str = results["result"];
            }
        }

        string outwords = "";
        foreach (Seg s in segs)
            outwords += s.str;

        Output output = new Output();
        output.words = outwords;
        output.hasKeys = MatchKeys(outwords);

        silentFromStart = false;
        silentTime = 0;

        foreach (GameObject go in resultGos)
            go.SendMessage("OnVoiceRecognitionInterface_Result", output, SendMessageOptions.DontRequireReceiver);
    }

    bool[] MatchKeys(string output)
    {
        if (matchPinyin)
            output = ConvertToPinyin(output);

        bool[] has = new bool[keywords.Length];
        for(int i=0;i<keywords.Length;i++)
        {
            if(matchPinyin)
                has[i] = (output.IndexOf(ConvertToPinyin(keywords[i])) >= 0);
            else
                has[i] = (output.IndexOf(keywords[i]) >= 0);
        }

        return has;
    }

    string ConvertToPinyin(string chr)
    {
        return Pinyin.GetPinyin(chr)+" ";
    }

}
